import unittest
from enum import Enum, auto, unique, IntEnum
# 枚举类
# class HttpStatus(Enum):
#     OK = 200
#     BAD_REQUEST = 400
#     FORBIDDEN = 403
#     NOT_FOUND = 404
#     REQUEST_TIMEOUT = 408
#     SERVICE_UNAVAILABLE = 500
#
# print('Member: {}'.format(HttpStatus.OK))               # Member: HttpStatus.OK
# print('Member name: {}'.format(HttpStatus.OK.name))     # Member name: OK
# print('Member value: {}'.format(HttpStatus.OK.value))   # Member value: 200
# print(repr(HttpStatus.OK))                              # <enum 'HttpStatus'>
# print(type(HttpStatus.OK))                              # <HttpStatus.OK: 200>
# print(isinstance(HttpStatus.OK, HttpStatus))            # True

# 迭代枚举
# 创建
class HttpStatus(Enum):
    OK = 200
    BAD_REQUEST = 400
    FORBIDDEN = 403
    NOT_FOUND = 404
    REQUEST_TIMEOUT = 408
    SERVICE_UNAVAILABLE = 500
    OTHER = auto.value

# 迭代
# for status in HttpStatus:
#     print('{} : {}'.format(status.name, status.value))
# 第二种迭代方式


# 枚举成员与属性访问
# print(HttpStatus(200)) # 通过枚举 value 进行访问，访问需要使用元组()的形式
# print(HttpStatus['OK']) # 通过枚举 name 进行访问，访问需要使用列表[]的形式
# 将属性赋予另一个 enum 成员
number = HttpStatus.OK
# print(number)

# @unique
# class HttpStatus(Enum):
#     OK = 200
#     BAD_REQUEST = 400
#     FORBIDDEN = 403
#     NOT_FOUND = 404
#     REQUEST_TIMEOUT = 408
#     SERVICE_UNAVAILABLE = 500
    # OTHER = 200
'''
们查看源代码，发现加入此装饰器的枚举类型，unique 方法会将其 __members__.items() 进行遍历，
追加到 duplicates 列表中，如果发现列表不为空，则抛出如上异常信息。
'''

# 此功能用于我们在使用枚举时，只在意枚举的标识符的含义而不在意值的情况下，但是如果需要与字符串或整数混合使用就要额外注意
class TestEnum(unittest.TestCase):
    def test_auto_number(self):
        class Color(Enum):
            red = auto()
            blue = auto()
            green = auto()
        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])

    def test_auto_name(self):
        class Color(Enum):
            def _generate_next_value_(self, start, count, last):
                return self

            red = auto()
            blue = auto()
            green = auto()

        self.assertEqual(list(Color), [Color.red, Color.blue, Color.green])
        self.assertEqual(Color.red.value, 'red')
        self.assertEqual(Color.blue.value, 'blue')
        self.assertEqual(Color.green.value, 'green')

# 枚举对象可以进行比较，但是不能进行值比较，如果需要进行值比较则需要枚举对象继承 IntEnum 对象
# class TestEnum2(unittest.TestCase):
#     class Season(IntEnum):
#         SPRING = 1
#         SUMMER = 2
#         AUTUMN = 3
#         WINTER = 4
#
#     def test_comparisons(self):
#         season = self.Season
#
#         self.assertEqual(season.SPRING, 1)
#
#         class Part(Enum):
#             SPRING = 1
#             CLIP = 2
#             BARREL = 3
#
#         self.assertNotEqual(Part.SPRING, 1)
#         self.assertNotEqual(Part.SPRING, season.SPRING)
'''
以看到继承了 IntEnum 的 Season 可以进行值的比较，
而继承了 Enum 的 Part 则不能进行值比较，并且 IntEnum 类型与 Enum 类型也不能进行比较，即使属性和值一样
'''
# TestEnum2().test_comparisons()

# 枚举方法内置方法
class Mood(Enum):
    FUNKY = (1, "hello")
    HAPPY = (3, "world")

    def describe(self):
        return self.name, self.value

    def __init__(self, num, nice):
        self.num = num
        self.nice = nice

    def __str__(self):
        return 'my custom str! {0}'.format(self.value)

    @classmethod
    def favorite_mood(cls):
        return cls.HAPPY

    @property
    def testValue(self):
        return self.nice + ':' + str(self.num)

# print(Mood.favorite_mood())     # my custom str! (3, 'world')
# print(Mood.HAPPY.describe())    # ('HAPPY', (3, 'world'))
# print(str(Mood.FUNKY))          # my custom str! (1, 'hello')
# print(Mood.FUNKY.testValue)     # hello:1

# 不同于 java 中的枚举类, python 中的枚举类是可以被继承的，但是被继承的枚举类规定其不能定义任何成员，但可以定义抽象方法。
class EnumExtend(unittest.TestCase):

    def test_extending(self):
        class Shade(Enum):
            def shade(self):
                print(self.name)

        class Color(Shade):
            red = 1
            green = 2
            blue = 3
        with self.assertRaises(TypeError):
            class MoreColor(Color):
                cyan = 4
                magenta = 5
                yellow = 6

    def test_extending2(self):
        class Shade(Enum):
            def shade(self):
                return self.name

        class Color(Shade):
            def hex(self):
                return '%s nice!' % self.value

        class MoreColor(Color):
            cyan = 4
            magenta = 5
            yellow = 6
        self.assertEqual(MoreColor.magenta.shade(), 'magenta')
        self.assertEqual(MoreColor.magenta.hex(), '5 nice!')

